#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <arpa/inet.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

#include <unistd.h>

int get_mac_total(uint8_t *macp){  // 计算mac地址的所有位置上字节数值
    int total = 0;
    for(int i=0;i<6;i++){
        total += macp[i];
    }
    return total;
}

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

    // mac首部：6+6+2 = 14  + 数据部分：46~1500 + CRC（4）
    // IP 首部: 20/24
    // UDP首部： 8 
    // 数据：   ...
    char buf[1518] = ""; // 数据报的缓冲区
    ssize_t len = 0; // 数据报的长度

    struct ether_header *mac = NULL;  // mac首部
    struct iphdr  *ip = NULL;  // ip 首部
    struct udphdr *udp = NULL;  // udp首部

    char destmac[18] = ""; 
    char srcmac[18] = ""; 

    char destip[16] ="";  // 目标IP
    char srcip[16] = ""; // 源IP
    while(1){
        len = recvfrom(sockfd, buf, 1518, 0, NULL, NULL);
        // printf("recv(%ld)\n", len);
        if(len > 0){
            // 拆分MAC首部
            mac = (struct ether_header *)buf;  // 将buf中的前14个字节转化为结构体的成员数据
            if(get_mac_total(mac->ether_dhost) == 0 || get_mac_total(mac->ether_shost) == 0) continue;
            sprintf(destmac, "%02x:%02x:%02x:%02x:%02x:%02x", mac->ether_dhost[0],mac->ether_dhost[1],mac->ether_dhost[2],mac->ether_dhost[3],mac->ether_dhost[4],mac->ether_dhost[5]);
            sprintf(srcmac, "%02x:%02x:%02x:%02x:%02x:%02x", mac->ether_shost[0],mac->ether_shost[1],mac->ether_shost[2],mac->ether_shost[3],mac->ether_shost[4],mac->ether_shost[5]);
            // printf("%s->%s(0x%04x)\n", srcmac, destmac,  ntohs(mac->ether_type));

            // 拆分IP首部
            if(mac->ether_type == htons(0x0800)){
                ip = (struct iphdr *)(buf+14);
                inet_ntop(AF_INET, &ip->saddr, srcip, 16);
                inet_ntop(AF_INET, &ip->daddr, destip, 16);

                // printf("%s(%s)->%s(%s) protocol(%d)\n", srcmac,srcip, destmac, destip, ip->protocol);

                // 拆分UDP
                if(ip->protocol == 17){
                    // buf+ 14 + ip首部长度*4
                    udp = (struct udphdr *)(buf+14+ ip->ihl*4);

                    //udp 的数据位置:    buf+ 14 + ip首部长度*4 + 8
                    char *data = buf+14+ ip->ihl*4+8;
                    if(strlen(data) >= 0  && udp->dest == htons(9000))
                        printf("%s(%s:%d)->%s(%s:%d): %s\n", srcmac,srcip,ntohs(udp->source), destmac, destip, ntohs(udp->dest), data );
                }

            }
        }
        // usleep(1000*200);
    }

    return 0;
}
